package org.wdm.analysis;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.wdm.beans.Crime;
import org.wdm.beans.Route;
import org.wdm.beans.Step;

/**
 *
 * @author iakopap
 */
public class SimpleEvaluator implements Evaluator {

    //Mapping crimes into a map of identifiers
    private static final Map<String, Integer> CRIMES;
    //Mapping travel-modes into a map of identifiers
    private static final Map<String, Integer> MODES;
    //Crime's weights for each travel-mode
    private static final double[][] CW = {
        {0.1, 0.1, 0.4},
        {0.1, 0.4, 0.6},
        {0.1, 0.5, 0.9},
        {1.0, 0.8, 0.2},
        {0.1, 0.3, 1.0},
        {0.2, 0.6, 0.9},
        {0.2, 0.1, 0.5},
        {0.1, 0.2, 0.4},
        {0.1, 0.3, 0.6},
        {0.1, 0.3, 0.7},
        {0.1, 0.1, 0.6}
    };
    //Crime's co-relation matrix directed specific
    private static final double[][] CRM = {
        {1.0, 0.6, 0.9, 0.1, 0.7, 0.3, 0.7, 0.3, 0.8, 0.7, 0.5},
        {0.6, 1.0, 0.7, 0.1, 0.8, 0.4, 0.2, 0.4, 0.1, 0.6, 0.4},
        {0.9, 0.7, 1.0, 0.1, 0.8, 0.5, 0.6, 0.3, 0.6, 0.6, 0.4},
        {0.1, 0.1, 0.1, 1.0, 0.2, 0.1, 0.1, 0.3, 0.1, 0.5, 0.4},
        {0.7, 0.8, 0.8, 0.2, 1.0, 0.9, 0.7, 0.6, 0.5, 0.8, 0.5},
        {0.3, 0.4, 0.5, 0.1, 0.9, 1.0, 0.4, 0.8, 0.4, 0.4, 0.4},
        {0.7, 0.2, 0.6, 0.1, 0.7, 0.4, 1.0, 0.7, 0.7, 0.8, 0.5},
        {0.3, 0.4, 0.3, 0.3, 0.6, 0.8, 0.7, 1.0, 0.4, 0.6, 0.5},
        {0.8, 0.1, 0.6, 0.1, 0.5, 0.4, 0.7, 0.4, 1.0, 0.4, 0.5},
        {0.7, 0.6, 0.6, 0.5, 0.8, 0.4, 0.8, 0.6, 0.4, 1.0, 0.6},
        {0.5, 0.4, 0.4, 0.4, 0.5, 0.4, 0.5, 0.5, 0.5, 0.6, 1.0}
    };

    static {
        //Mapping crimes identifiers
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("burglary", 0);
        map.put("anti-social-behaviour", 1);
        map.put("robbery", 2);
        map.put("vehicle-crime", 3);
        map.put("violent-crime", 4);
        map.put("public-disorder-weapons", 5);
        map.put("shoplifting", 6);
        map.put("criminal-damage-arson", 7);
        map.put("other-theft", 8);
        map.put("drugs", 9);
        map.put("other-crime", 10);
        CRIMES = map;
//        CRIMES = Collections.unmodifiableMap(map);

        //Mapping travel-modes identifiers
        map = new HashMap<String, Integer>();
        map.put("DRIVING", 0);
        map.put("TRANSPORT", 1);
        map.put("WALKING", 2);
        MODES = map;
//        MODES = Collections.unmodifiableMap(map);
    }

    public double evaluate(Route route) {
        //Getting all the steps within this route
        List<Step> steps = route.getSteps();

        //Where each step's score stored
        double[] stepScores = new double[steps.size()];

        //Traverse through each step and evaluate it
        for (int s = 0; s < steps.size(); s++) {
            //Getting next step
            Step step = steps.get(s);

            //Getting the travel-mode id
            int m = MODES.get(step.getTravelMode());

            //Getting the step's distance
            double ds = step.getDistance();

            //Getting the step's duration
            int ts = step.getDuration();

            //Getting all the crimes within this step
            List<Crime> crimes = step.getCrimesList();

            //No crimes safe step
            if (crimes.isEmpty()) {
                stepScores[s] = 0;
                continue;
            }

            //Building the frequency histogram of the crimes
            int[] n = new int[CRIMES.size()];
            int ns = 0;
            for (Crime crime : crimes) {
                String category = crime.getCategory();
                try {
                    int id = CRIMES.get(category);
                    n[id]++;
                    ns++;
                } catch (Exception e) {
                    System.out.println(category);
                }
            }

            //Where each crime's category score stored
            double[] crimeScores = new double[CRIMES.size()];

            //Traverse through each crime category and evaluate it
            for (int c = 0; c < crimeScores.length; c++) {
                double sum = 0.0;
                for (int j = 0; j < n.length; j++) {
                    sum += CRM[c][j] * n[j];
                }
                double acorc = 0;
                //Calculating the weighted average corelation for crime category c
                if (ns != 0) {
                    acorc = sum / ns;
                }

                //Calculating the final crime category score, based on travel-mode
                crimeScores[c] = CW[c][m] * ((double) n[c] / ns) * acorc;
            }

            //Calculating the final score for each step
            for (int c = 0; c < crimeScores.length; c++) {
                stepScores[s] += crimeScores[c];
            }

            //Take into account the step's distance and duration parameters
            //stepScores[s] *= 1 / (ds + 1) * (ts + 1));
            step.setCriminalityScore(stepScores[s]);
        }

        //Calculating the final route's score
        double score = 0.0;
        for (int s = 0; s < stepScores.length; s++) {
            score += stepScores[s];
        }

        route.setCriminalityScore(score);
        return score;
    }
}
